home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / forms / FORMS / fselect.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  11KB  |  373 lines

  1. /*
  2.  * fdesign.c
  3.  *
  4.  * This file belongs to the goodies of the Forms Library.
  5.  *
  6.  * It contains the file selector.
  7.  *
  8.  * Written by: Mark Overmars and Trevor Paquette
  9.  *
  10.  * Version 2.2 b
  11.  * Date: Jun 18, 1993
  12.  */
  13.  
  14. #include <malloc.h>
  15. #include <unistd.h>
  16. #include <strings.h>
  17. #include <stdio.h>
  18. #include <sys/types.h>
  19. #include <dirent.h>
  20. #include <sys/stat.h>
  21. #include <sys/time.h>
  22.  
  23. #include "forms.h"
  24. /* the following is strictly for compilation on an Ultrix
  25.  * with gcc
  26.  */
  27. #if defined(__vax__) || defined(__STRICT_ANSI__)
  28. extern int scandir(const char *, struct dirent **[],
  29.            int (*select)(struct dirent *),
  30.            int (*howsort)(struct dirent **, struct dirent **));
  31. extern int alphasort(struct dirent **, struct dirent **);
  32. #endif
  33.  
  34. static FL_FORM *fsform;
  35. static FL_OBJECT *messageobj, *selectionobj, *readyobj, *cancelobj,
  36.         *selectobj, *directoryobj, *patternobj;
  37.  
  38. static char fl_directory[256];        /* Current directory */
  39. static char fl_pattern[256];        /* Current pattern */
  40. static char fl_filename[256];        /* Current selected file name */
  41.  
  42. /*------------------- Pattern matching --------------------------*/
  43. /* Adapted from Rich Salz. */
  44.  
  45. static int do_matching(char *, char *);
  46.  
  47. static int match_star(char *s, char *p)
  48. {
  49.  int result;
  50.  while( (result = do_matching(s, p)) == FALSE) /* gobble up * match */
  51.    if(*++s == NULL) return -1;
  52.  return result;
  53. }
  54.  
  55. static int do_matching(char *s, char *p)
  56. /* match string "s" to pattern "p" */
  57. {
  58.  int last, matched, reverse;
  59.  for ( ; *p; s++, p++)
  60.  {
  61.    if(*s == NULL) return (*p == '*' && *++p == NULL ? TRUE : -1);
  62.  
  63.    switch(*p)
  64.    { /* parse pattern */
  65.      case '\\': /* Literal match with following character. */
  66.     if(*s != *++p) return FALSE;
  67.     continue;
  68.  
  69.      default  : /*literal match*/
  70.     if(*s != *p) return FALSE;
  71.     continue;
  72.  
  73.      case '?' : /* Match anything. */
  74.     continue;
  75.  
  76.      case '*' : /* Trailing star matches everything. */
  77.     return (*++p ? match_star(s, p) : TRUE);
  78.  
  79.      case '[':  /* [!....] means inverse character class. */
  80.     if (reverse = p[1] == '!') p++;
  81.  
  82.     for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
  83.       /* This next line requires a good C compiler. */
  84.       /*     range?        (in bounds)                  (equal) */
  85.       if((*p == '-') ? (*s <= *++p && *s >= last ) : (*s == *p))
  86.         matched = TRUE;
  87.  
  88.     if(matched == reverse) return FALSE;
  89.     continue;
  90.    }
  91.  }
  92.  return *s == NULL;
  93. }
  94.  
  95. static int wildmat(char *s, char *p)
  96. {
  97.  if (*p == NULL && *s != '.') return TRUE;
  98.  else if (*p == NULL) return FALSE;
  99.  else if ( (*p == '?' || *p == '*' ) && *s == '.') return FALSE;
  100.  else return do_matching(s, p) == TRUE;
  101. }
  102.  
  103. static int match_pattern(struct dirent *file)
  104. {
  105.   char tmpstr[256];
  106.   struct stat fstat;
  107.   strcpy(tmpstr,fl_directory);
  108.   if (strlen(fl_directory)==0 || fl_directory[strlen(fl_directory)-1]!='/')
  109.     strcat(tmpstr,"/");
  110.   strcat(tmpstr,file->d_name);
  111.   stat(tmpstr,&fstat);
  112.   if (fstat.st_mode & S_IFDIR) return TRUE;
  113.   return(wildmat(file -> d_name, fl_pattern));
  114. }
  115.  
  116. /*------------------- Routine to correct directory ------------*/
  117.  
  118. static void set_dirpath()
  119. /* Corrects the directory path. */
  120. {
  121.   char tmpstr[256];
  122.   int i,j,k;
  123.   if (fl_directory[0] == NULL)
  124.     strcpy(tmpstr,"/");
  125.   else if (fl_directory[0] != '/')
  126.   {
  127.     getcwd(tmpstr,256);
  128.     strcat(tmpstr,"/");
  129.     strcat(tmpstr,fl_directory);
  130.   }
  131.   else
  132.     strcpy(tmpstr,fl_directory);
  133.   for (i=0; i < strlen(tmpstr); i++)
  134.   {
  135.     if (tmpstr[i] == '/' && tmpstr[i+1] == '.' && 
  136.         (tmpstr[i+2] == '/' || tmpstr[i+2] == NULL))
  137.     {
  138.       for (j=i+2; tmpstr[j-1] != NULL; j++) tmpstr[j-2] = tmpstr[j];
  139.       i--;
  140.     }
  141.     else if (tmpstr[i] == '/' && tmpstr[i+1] == '.' && tmpstr[i+2] == '.' &&
  142.         (tmpstr[i+3] == '/' || tmpstr[i+3] == NULL))
  143.     {
  144.       if (i==0)
  145.       {
  146.         for (j=i+3; tmpstr[j-1] != NULL; j++) tmpstr[j-3] = tmpstr[j];
  147.         i = -1;
  148.       }
  149.       else
  150.       {
  151.     for (k=i-1; tmpstr[k] != '/'; k--) ;
  152.         for (j=i+3; tmpstr[j-1] != NULL; j++) tmpstr[j+k-i-3] = tmpstr[j];
  153.         i = k-1;
  154.       }
  155.     }
  156.   }
  157.   if (tmpstr[0] == NULL) strcpy(tmpstr,"/");
  158.   strcpy(fl_directory,tmpstr);
  159.   fl_set_object_label(directoryobj,tmpstr);
  160. }
  161.  
  162. /*------------------- Routine to fill in the browser ------------*/
  163.  
  164. static void fillin_choices()
  165. /* Fills in the choices in the library based on the current directory and
  166.    pattern. */
  167. {
  168.   struct dirent **namelist;
  169.   struct stat fstat;
  170.   int i,fnumb;
  171.   char tmpstr[256];
  172.   
  173.   /* Read the directory contents */
  174.   fnumb = scandir(fl_directory, &namelist, match_pattern, alphasort);
  175.   if (fnumb < 0)
  176.   {
  177.     fl_show_message("Cannot open:", fl_directory, "for reading.");
  178.     fl_clear_browser(selectobj);
  179.     return;
  180.   }
  181.  
  182.   /* Fill in the browser */
  183.   fl_freeze_form(fsform);
  184.   fl_clear_browser(selectobj);
  185.   for (i=0; i<fnumb; i++)
  186.   {
  187.     strcpy(tmpstr,fl_directory);
  188.     if (strlen(fl_directory)==0 || fl_directory[strlen(fl_directory)-1]!='/')
  189.       strcat(tmpstr,"/");
  190.     strcat(tmpstr,namelist[i]->d_name);
  191.     stat(tmpstr,&fstat);
  192.     if (fstat.st_mode & S_IFDIR)
  193.       sprintf(tmpstr,"D %s",namelist[i]->d_name);
  194.     else
  195.       sprintf(tmpstr,"  %s",namelist[i]->d_name);
  196.     fl_add_browser_line(selectobj,tmpstr);
  197.     free(namelist[i]);
  198.   }
  199.   fl_unfreeze_form(fsform);
  200.   free(namelist);
  201. }
  202.  
  203. /*----------------------- The Callback Routines -----------------*/
  204.  
  205. static int lastline = 0;
  206. static long lastsec = 0;
  207. static long lastusec = 0;
  208.  
  209. static int select_cb(FL_OBJECT *obj, long arg)
  210. /* user selected something in the selector */
  211. {
  212.   char seltext[256];
  213.   int dir, i;
  214.   struct timeval tp;
  215.   struct timezone tzp;
  216.   strcpy(seltext,fl_get_browser_line(obj,fl_get_browser(obj)));
  217.   dir = seltext[0] == 'D';
  218.   for (i= 2; i<=strlen(seltext); i++) seltext[i-2] = seltext[i];
  219.   if (dir)
  220.   {
  221.     if (strlen(fl_directory)== 0 || fl_directory[strlen(fl_directory)-1] != '/')
  222.       strcat(fl_directory,"/");
  223.     strcat(fl_directory,seltext);
  224.     set_dirpath();
  225.     fillin_choices();
  226.     return 0;
  227.   }
  228.   else
  229.   {
  230.     fl_set_input(selectionobj,seltext);
  231.     strcpy(fl_filename,seltext);
  232.     gettimeofday(&tp,&tzp);
  233.     if (lastline == fl_get_browser(obj))
  234.     {
  235.       if (1000000*(tp.tv_sec - lastsec) + (tp.tv_usec - lastusec) < 400000)
  236.     return 1;
  237.     }
  238.     lastline = fl_get_browser(obj);
  239.     lastsec = tp.tv_sec; lastusec = tp.tv_usec;
  240.     return 0;
  241.   }
  242. }
  243.  
  244. static void directory_cb(FL_OBJECT *obj, long arg)
  245. /* User wants to change the directory */
  246. {
  247.   strcpy(fl_directory,fl_show_input("Enter new directory:",fl_directory));
  248.   set_dirpath();
  249.   fillin_choices();
  250. }
  251.  
  252. static void pattern_cb(FL_OBJECT *obj, long arg)
  253. /* User wants to change the pattern */
  254. {
  255.   strcpy(fl_pattern,fl_show_input("Enter new pattern:",fl_pattern));
  256.   fl_set_object_label(patternobj,fl_pattern);
  257.   fillin_choices();
  258. }
  259.  
  260. static void filename_cb(FL_OBJECT *obj, long arg)
  261. /* User changed the file name. Nothing needs to be done */
  262. {
  263. }
  264.  
  265. /*------------------- The form definition -----------------------*/
  266.  
  267. static void create_fs_form(void)
  268. {
  269.   FL_OBJECT *obj;
  270.   fsform = fl_bgn_form(FL_NO_BOX,530.0,460.0);
  271.   obj = fl_add_box(FL_UP_BOX,0.0,0.0,530.0,460.0,"");
  272.     fl_set_object_color(obj,12,47);
  273.   messageobj = obj = fl_add_box(FL_BORDER_BOX,20.0,410.0,490.0,30.0,"A message");
  274.     fl_set_object_color(obj,53,47);
  275.   selectionobj = obj = fl_add_input(FL_NORMAL_INPUT,290.0,270.0,220.0,30.0,"file name");
  276.     fl_set_object_boxtype(obj,FL_SHADOW_BOX);
  277.     fl_set_object_color(obj,52,9);
  278.     fl_set_object_align(obj,FL_ALIGN_TOP);
  279.     fl_set_object_lstyle(obj,FL_BOLD_STYLE);
  280.     fl_set_call_back(obj,filename_cb,0);
  281.   readyobj = obj = fl_add_button(FL_RETURN_BUTTON,380.0,120.0,130.0,40.0,"Ready");
  282.   cancelobj = obj = fl_add_button(FL_NORMAL_BUTTON,380.0,50.0,130.0,40.0,"Cancel");
  283.   obj = fl_add_box(FL_SHADOW_BOX,20.0,20.0,240.0,300.0,"");
  284.   selectobj = obj = fl_add_browser(FL_HOLD_BROWSER,20.0,20.0,240.0,300.0,"");
  285.     fl_set_object_boxtype(obj,FL_BORDER_BOX);
  286.     fl_set_object_color(obj,53,9);
  287.   directoryobj = obj = fl_add_text(FL_NORMAL_TEXT,90.0,370.0,420.0,30.0,"Text");
  288.     fl_set_object_boxtype(obj,FL_BORDER_BOX);
  289.     fl_set_object_color(obj,52,47);
  290.     fl_set_object_lsize(obj,10.000000);
  291.   obj = fl_add_text(FL_NORMAL_TEXT,10.0,370.0,80.0,30.0,"directory");
  292.     fl_set_object_align(obj,FL_ALIGN_RIGHT);
  293.     fl_set_object_lstyle(obj,FL_BOLD_STYLE);
  294.   patternobj = obj = fl_add_text(FL_NORMAL_TEXT,90.0,340.0,420.0,30.0,"Text");
  295.     fl_set_object_boxtype(obj,FL_BORDER_BOX);
  296.     fl_set_object_color(obj,52,47);
  297.     fl_set_object_lsize(obj,10.000000);
  298.   obj = fl_add_text(FL_NORMAL_TEXT,10.0,340.0,80.0,30.0,"pattern");
  299.     fl_set_object_align(obj,FL_ALIGN_RIGHT);
  300.     fl_set_object_lstyle(obj,FL_BOLD_STYLE);
  301.   obj = fl_add_button(FL_HIDDEN_BUTTON,90.0,370.0,420.0,30.0,"");
  302.     fl_set_object_lsize(obj,FL_SMALL_FONT);
  303.     fl_set_call_back(obj,directory_cb,0);
  304.   obj = fl_add_button(FL_HIDDEN_BUTTON,90.0,340.0,420.0,30.0,"");
  305.     fl_set_call_back(obj,pattern_cb,0);
  306.   fl_end_form();
  307. }
  308.  
  309. /*----------------------- The Main Routine ----------------------*/
  310.  
  311. static int created = 0;        /* Whether form is created. */
  312. static char combined[512];    /* Used to contain the combined file name. */
  313.  
  314. char *fl_show_file_selector(char message[],char dir[],char pat[],char fname[])
  315. /* Displays the file selector. Returns whether Ready was pressed. */
  316. {
  317.   FL_OBJECT *obj;
  318.  
  319.   /* Create form if required. */
  320.   if (!created)
  321.   {
  322.     strcpy(fl_directory,".");
  323.     strcpy(fl_pattern,"*");
  324.     fl_filename[0] = NULL;
  325.     create_fs_form();
  326.     created = 1;
  327.   }
  328.  
  329.   /* Fill in the fields. */
  330.   fl_set_object_label(messageobj,message);
  331.   if (dir != NULL && dir[0] != '\0') strcpy(fl_directory,dir);
  332.   if (pat != NULL && pat[0] != '\0') strcpy(fl_pattern,pat);
  333.   if (fname != NULL && fname[0] != '\0') strcpy(fl_filename,fname);
  334.   set_dirpath();
  335.   fl_set_object_label(patternobj,fl_pattern);
  336.   fl_set_input(selectionobj,fl_filename);
  337.   fillin_choices();
  338.  
  339.   /* Show the form. */
  340.   fl_set_browser_fontstyle(selectobj,FL_FIXED_STYLE);
  341.   fl_set_object_focus(fsform,selectionobj);
  342.   fl_deactivate_all_forms();
  343.   fl_show_form(fsform,FL_PLACE_CENTER,FALSE,NULL);
  344.   do {
  345.     obj = fl_do_only_forms();
  346.     if (obj == selectobj)
  347.       if (select_cb(selectobj,0)) break;
  348.   } while (obj != readyobj && obj != cancelobj);
  349.   fl_hide_form(fsform);
  350.   fl_activate_all_forms();
  351.  
  352.   /* Return value */
  353.   if (obj == cancelobj) return NULL;
  354.   strcpy(fl_filename,fl_get_input(selectionobj));
  355.   strcpy(combined,fl_directory);
  356.   if (strlen(fl_directory) == 0 || fl_directory[strlen(fl_directory)-1] != '/')
  357.     strcat(combined,"/");
  358.   strcat(combined,fl_filename);
  359.   return combined;
  360. }
  361.  
  362. char *fl_get_directory()
  363. /* returns a pointer to the directory */
  364.   { return fl_directory; }
  365.  
  366. char *fl_get_pattern()
  367. /* returns a pointer to the pattern */
  368.   { return fl_pattern; }
  369.  
  370. char *fl_get_filename()
  371. /* returns a pointer to the filename */
  372.   { return fl_filename; }
  373.